package com.zdpx.pxframework.auth.service.impl;

import cn.hutool.core.util.IdUtil;
import com.zdpx.pxframework.auth.service.TokenService;
import com.zdpx.pxframework.auth.service.UserService;
import com.zdpx.pxframework.auth.vo.form.LoginInfoForm;
import com.zdpx.pxframework.auth.vo.vo.LoginInfoVo;
import com.zdpx.pxframework.core.constant.RedisKeyConstant;
import com.zdpx.pxframework.core.constant.SecurityConstant;
import com.zdpx.pxframework.core.constant.TokenConstant;
import com.zdpx.pxframework.core.exception.GlobalException;
import com.zdpx.pxframework.core.pojo.LoginUser;
import com.zdpx.pxframework.core.util.IpUtil;
import com.zdpx.pxframework.core.util.JwtUtil;
import com.zdpx.pxframework.core.util.RequestUtil;
import com.zdpx.pxframework.core.vo.CodeMsg;
import com.zdpx.pxframework.core.vo.Result;
import com.zdpx.pxframework.security.auth.AuthUtil;
import com.zdpx.pxframework.security.utils.SecurityUtil;
import com.zdpx.pxframework.system.api.api.RemoteDepartmentInfoService;
import com.zdpx.pxframework.system.api.api.RemoteMenuInfoService;
import com.zdpx.pxframework.system.api.api.RemoteRoleInfoService;
import com.zdpx.pxframework.system.api.api.RemoteUserInfoService;
import com.zdpx.pxframework.system.api.entity.UserInfo;
import com.zdpx.pxframework.system.api.enums.UserStatus;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 用户信息业务逻辑
 *
 * @Description:
 * @Author: Cheng XiaoXiao
 * @Date: 2022-02-27 19:22
 */
@Service
public class UserServiceImpl implements UserService {
    @Resource
    RemoteUserInfoService remoteUserInfoService;
    @Resource
    RemoteMenuInfoService remoteMenuInfoService;
    @Resource
    RemoteRoleInfoService remoteRoleInfoService;
    @Resource
    RemoteDepartmentInfoService remoteDepartmentInfoService;

    @Resource
    BCryptPasswordEncoder bCryptPasswordEncoder;
    @Resource
    private TokenService tokenService;

    /**
     * 进行用户登录
     *
     * @param loginInfoForm 用户登录信息
     * @return 登录后信息
     */
    @Override
    public LoginInfoVo login(LoginInfoForm loginInfoForm) {
        Result<UserInfo> userInfoResult = remoteUserInfoService.getUserInfoByUserName(loginInfoForm.getUserName(), SecurityConstant.INNER);
        UserInfo userInfo = userInfoResult.getData();
        if (userInfo == null) {
            throw new GlobalException(CodeMsg.USER_PASSWORD_INCORRENT);
        }

        //判断用户状态
        if (UserStatus.DISABLE.getCode().equals(userInfo.getStatus())) {
            throw new GlobalException(CodeMsg.USER_LOCKED);
        }

        //校验用户密码是否正确
        if (!bCryptPasswordEncoder.matches(loginInfoForm.getPassword(), userInfo.getPassword())) {
            throw new GlobalException(CodeMsg.USER_PASSWORD_INCORRENT);
        }


        String token = IdUtil.fastUUID();

        LoginUser loginUser = new LoginUser();
        loginUser.setId(userInfo.getId());
        loginUser.setUserName(userInfo.getUserName());
        loginUser.setNickName(userInfo.getNickName());
        loginUser.setToken(token);
        loginUser.setIp(IpUtil.getIpAddr(RequestUtil.getRequest()));

        //查询权限信息
        Result<Set<String>> menuKeysResult = remoteMenuInfoService.getMenuKeysByUserId(userInfo.getId(), SecurityConstant.INNER);
        loginUser.setPermissions(menuKeysResult.getData());

        //查询角色信息
        Result<Set<String>> roleKeysResult = remoteRoleInfoService.getRoleKeysByUserId(userInfo.getId(), SecurityConstant.INNER);
        loginUser.setRoles(roleKeysResult.getData());

        //查询用户的部门信息
        Result<List<String>> departmentIdResult = remoteDepartmentInfoService.listDepartmentIdsByUserId(userInfo.getId(), SecurityConstant.INNER);
        loginUser.setDepartmentIds(new HashSet<>(departmentIdResult.getData()));

        //刷新token
        tokenService.refreshToken(loginUser);

        // Jwt存储信息
        Map<String, Object> claimsMap = new HashMap<String, Object>();
        claimsMap.put(SecurityConstant.USER_KEY, token);
        claimsMap.put(SecurityConstant.USER_ID, loginUser.getId());
        claimsMap.put(SecurityConstant.USER_NAME, loginUser.getUserName());

        LoginInfoVo loginInfoVo = new LoginInfoVo();
        loginInfoVo.setToken(TokenConstant.PREFIX + JwtUtil.createToken(claimsMap));
        loginInfoVo.setExpireTime(RedisKeyConstant.EXPIRATION);

        return loginInfoVo;
    }

    /**
     * 进行用户注销操作
     */
    @Override
    public void logout() {
        String token = SecurityUtil.getToken();
        if (StringUtils.isNotEmpty(token)) {
            //获取用户key，在redis中进行删除
            String userKey = SecurityUtil.getUserKey();
            AuthUtil.logoutByUserKey(userKey);
        }

    }

    /**
     * 获取登录用户信息
     *
     * @return 登录用户信息
     */
    @Override
    public LoginUser getUserInfo() {
        return SecurityUtil.getLoginUser();
    }

}

